#ifndef _VC10EA_

#include "cTypes.h"
#include "BitLine.h"
#include "MemManager.h"
#include "DeltaLine.h"

#include <stdlib.h>
#ifndef	_TI_
#include <memory.h>
#endif 
#include <math.h> 

#endif //ndef _VC10EA_

#define LongMin			1023



/**************************************************************************************************

					  Pack_LongBitLine

**************************************************************************************************/
void Pack_LongBitLine(BYTE *BL, int L, BYTE *Pool, int *Start, BYTE* Memory)
{
	int C1, PN, SZ, Io, Energy, i, j, P;

	int	 *Cnt1	   = (int*) ENCODER_MEMORY_GET_ADDRESS(ID_ENCODER_Cnt1,     Memory);
	BYTE *Sign	   =		ENCODER_MEMORY_GET_ADDRESS(ID_ENCODER_Sign,     Memory); 
	BYTE *BitLine1 =        ENCODER_MEMORY_GET_ADDRESS(ID_ENCODER_BitLine1, Memory);


	if (L <= LongMin) {  
		C1 = GetCounter1(0, BL, L);
		PutNumber(C1, L, Pool, Start);
		Pack_IncDensity_BitLine(0, BL, Pool, Start, C1, L);
		return;
	}

    
	PN = (L / UBoundCNL) + 1;
  
	Io = 0;
	for (i = 0; i<PN; i++) {
		SZ = (L - Io) / (PN - i);
		Cnt1[i] = GetCounter1(Io, BL, SZ);
		Io = Io + SZ;
	}
  
	Energy = Cnt1[0];
	for (i = 1; i<PN; i++) {
		if (Cnt1[i] < Cnt1[i - 1]) SetBit(Sign, i - 1); else ClrBit(Sign, i - 1);
		Energy += abs(Cnt1[i] - Cnt1[i - 1]);
	}
	PutNumber_Tab(Energy,4,Pool,Start);
 
	C1 = GetCounter1(0, Sign, PN - 1);
	PutNumber(C1, PN - 1, Pool, Start);
	Pack_Bit_Line(0, Sign, Pool, Start, C1, PN - 1);
 
	memset(BitLine1,0, ((PN - 1 + Energy) / 8) +1);
	j = 0; P = 0;
	for (i = 0; i<(PN - 1); i++) {
		j = j + abs(Cnt1[i] - P) + 1;
		SetBit(BitLine1, j - 1);
		P = Cnt1[i];
	}
	Pack_IncDensity_BitLine(0, BitLine1, Pool, Start, PN - 1, PN - 1 + Energy);
	
	Io = 0;
	for (i = 0; i<PN; i++) {
		SZ = (L - Io) / (PN - i);
		Pack_IncDensity_BitLine (Io, BL, Pool, Start, Cnt1[i], SZ);
		Io = Io + SZ;
	}

}
/**************************************************************************************************

					  Unpack_LongBitLine

**************************************************************************************************/
void Unpack_LongBitLine(BYTE *BL, int L, BYTE *Pool, int *Start, int *Counter1, BYTE * Memory)
{
	int C1, PN, SZ, Io, Energy, i, j, k;

	int	 *Cnt1		= (int*) DECODER_MEMORY_GET_ADDRESS(ID_DECODER_Cnt1,     Memory);
	BYTE *Sign		=		 DECODER_MEMORY_GET_ADDRESS(ID_DECODER_Sign,     Memory); 
	BYTE *BitLine1	=        DECODER_MEMORY_GET_ADDRESS(ID_DECODER_BitLine1, Memory);


	if (L <= LongMin) {  
		C1 = GetNumber(L, Pool, Start); *Counter1 = C1;
		Unpack_IncDensity_BitLine(0, BL, Pool, Start, C1, L);
		return;
	}

	PN = (L / UBoundCNL) + 1;
    
	Energy = GetNumber_Tab(4,Pool,Start);
	C1 = GetNumber(PN - 1, Pool, Start);
	Unpack_Bit_Line(0, Sign, Pool, Start, C1, PN - 1);
	Unpack_IncDensity_BitLine(0, BitLine1, Pool, Start, PN - 1, PN - 1 + Energy);


	j = 0;
	while (!GetBit(BitLine1, j)) j++;
	Cnt1[0] = j; j++; Energy-= Cnt1[0];
	for (i = 1; i<(PN - 1); i++) {
		k=0; while (!GetBit(BitLine1, j+k)) k++;

		if (GetBit(Sign,i-1))  Cnt1[i] = Cnt1[i - 1]-k; else Cnt1[i] = Cnt1[i - 1]+k; 

		Energy -=k; j+=k+1;
	}
	if (GetBit(Sign,i-1))  Cnt1[i] = Cnt1[i - 1]-Energy; else Cnt1[i] = Cnt1[i - 1]+Energy; 


	Io = 0; *Counter1 = 0;
	for (i = 0; i<PN; i++) {
		SZ = (L - Io) / (PN - i);
		*Counter1 += Cnt1[i];
		Unpack_IncDensity_BitLine (Io, BL, Pool, Start, Cnt1[i], SZ);
		Io = Io + SZ;
	}

}




/**************************************************************************************************

					  Pack_Unsign_QDelta_Stream

**************************************************************************************************/
void Pack_Unsign_QDelta_Stream(char *US, int L, BYTE *Pool, int *Start, int Max, int Energy, BYTE *Memory)
{
	int i, j;

	BYTE *BitLine = ENCODER_MEMORY_GET_ADDRESS(ID_ENCODER_BitLine, Memory);


	if ((L == 1) || (Energy == 0) || (Energy == (Max * L))) return;

	if ((Energy*2) > (Max * L)) {
		for (i = 0; i<L; i++) US[i] = Max - US[i];
	    Energy = Max * L - Energy;
	}
  
	if (Energy == 1) {
		for (i = 0; i<L; i++) {
			if (US[i] == 1) {
				PutNumber(i, L - 1, Pool, Start);
				return;
			}
		}
	}
  
	memset(BitLine,0, ((L - 1 + Energy) / 8) +1);
	j = 0;
	for (i = 0; i<(L - 1); i++) {
		j += US[i] + 1;
		SetBit(BitLine, j - 1);
	}


	Pack_IncDensity_BitLine(0, BitLine, Pool, Start, L - 1, L - 1 + Energy);

}

void Pack_Unsign_QDelta_Stream_B(BYTE *US, int L, BYTE *Pool, int *Start, int Max, int Energy, BYTE *Memory)
{
	int i, j;
	BYTE *BitLine;


	BitLine =        ENCODER_MEMORY_GET_ADDRESS(ID_ENCODER_BitLine, Memory);

	if ((L == 1) || (Energy == 0) || (Energy == (Max * L))) return;

	if ((Energy*2) > (Max * L)) {
		for (i = 0; i<L; i++) US[i] = Max - US[i];
	    Energy = Max * L - Energy;
	}
  
	if (Energy == 1) {
		for (i = 0; i<L; i++) {
			if (US[i] == 1) {
				PutNumber(i, L - 1, Pool, Start);
				return;
			}
		}
	}
  
	memset(BitLine,0, ((L - 1 + Energy) / 8) +1);
	j = 0;
	for (i = 0; i<(L - 1); i++) {
		j += US[i] + 1;
		SetBit(BitLine, j - 1);
	}


	Pack_IncDensity_BitLine(0, BitLine, Pool, Start, L - 1, L - 1 + Energy);


}



/**************************************************************************************************

					  Unpack_Unsign_QDelta_Stream

**************************************************************************************************/
void Unpack_Unsign_QDelta_Stream(char *US, int L, BYTE *Pool, int *Start, int Max, int Energy, BYTE *Memory)
{
	int i, j, k;
	BYTE *BitLine;

	BitLine =        DECODER_MEMORY_GET_ADDRESS(ID_DECODER_BitLine, Memory);

	if (L == 1) { US[0]=Energy; return; } 
	
	if ((Energy == 0) || (Energy == (Max * L))) {
		Energy /= L;
		for (i=0; i<L; i++) US[i]=Energy;
		return;
	}

	if ((Energy*2) > (Max * L)) {
		Unpack_Unsign_QDelta_Stream(US, L, Pool, Start, Max, Max * L - Energy, Memory);
		for (i = 0; i<L; i++) US[i] = Max - US[i];
		return;
	}

  
	if (Energy == 1) {
		memset(US, 0, L*2);
		US[GetNumber(L - 1, Pool, Start)]=1;
		return;
	}
  
	Unpack_IncDensity_BitLine(0, BitLine, Pool, Start, L - 1, L - 1 + Energy);

	j = 0;
	for (i = 0; i<(L - 1); i++) {
		k = 0; while (!GetBit(BitLine, j+k)) k++;

		US[i] = k;

		Energy -=k; j+=k+1;
	}
	US[i] = Energy;

}




/**************************************************************************************************

					  Pack_Sign_QDelta_Stream

**************************************************************************************************/
void Pack_Sign_QDelta_Stream(char *QDelta, int Delta_Pnt, BYTE *Pool, int *Start, int Max, BYTE * Memory)
{
	int i, j, SP, Energy;
	BYTE *Sign, *BitLine;

	Sign	 =		  ENCODER_MEMORY_GET_ADDRESS(ID_ENCODER_Sign,     Memory); 
	BitLine  =        ENCODER_MEMORY_GET_ADDRESS(ID_ENCODER_BitLine,  Memory);



	while ((Delta_Pnt > Small_Stream) && (Max!=0))  {

#ifdef	_MMX_		
		j = INTEL_Delta_To_BitLine_Pos(QDelta, BitLine, Delta_Pnt);
#else

		j = 0;
		for (i = 0; i<Delta_Pnt; i++) {
			if (QDelta[i] == 0) {
				ClrBit(BitLine, i);
			} else {
				SetBit(BitLine, i);
		        if (QDelta[i] > 0) QDelta[j] = QDelta[i] - 1; else QDelta[j] = QDelta[i];
				j += 1;
			}
		}
#endif

		Pack_LongBitLine(BitLine, Delta_Pnt, Pool, Start, Memory);
		Delta_Pnt = j;
		
		if (Delta_Pnt==0) return;

#ifdef	_MMX_		
		j = INTEL_Delta_To_BitLine_Neg(QDelta, BitLine, Delta_Pnt);
#else

		j = 0;
		for (i = 0; i<Delta_Pnt; i++) {
			if (QDelta[i] == 0) {
				ClrBit(BitLine, i);
			} else {
				SetBit(BitLine, i);
		        if (QDelta[i] > 0) QDelta[j] = QDelta[i]; else QDelta[j] = QDelta[i]+1;
				j += 1;
			}
		}
#endif
		Pack_LongBitLine(BitLine, Delta_Pnt, Pool, Start, Memory);
		Delta_Pnt = j;

		Max--;
	}

	if ((Max==0) || (Delta_Pnt==0)) return;
  
	SP = 0; Energy = 0;
	for (i=0; i<Delta_Pnt; i++) {
		if (QDelta[i]!=0) {
			if (QDelta[i]<0) SetBit(Sign, SP); else ClrBit(Sign, SP);
			SP ++;
			QDelta[i]=abs(QDelta[i]);
			Energy += QDelta[i];
		} 
	}	
		
	PutNumber(Energy, Max*Delta_Pnt, Pool, Start);
	Pack_Unsign_QDelta_Stream(QDelta, Delta_Pnt, Pool, Start, Max, Energy, Memory);

	j = *Start;
	for (i = 0; i<SP; i++, j++) if (GetBit(Sign, i)) SetBit(Pool, j); else ClrBit(Pool, j); 
	*Start =j;


}

/**************************************************************************************************

					  Unpack_Sign_QDelta_Stream

**************************************************************************************************/

void Unpack_Sign_QDelta_Stream(char *RESTRICT QDelta, int Delta_Pnt, BYTE *RESTRICT Pool, int *RESTRICT Start, int Max,
							   BYTE * Memory)
{
	int i, k, Energy, V, L, nextL, LastIndex, Io, VIndexPnt;	
	int *BLIndex, *VIndex;
	BYTE *BitLine;
	char *Stream;

	BitLine  =         DECODER_MEMORY_GET_ADDRESS(ID_DECODER_BitLine, Memory);
	BLIndex	 = (int*)  DECODER_MEMORY_GET_ADDRESS(ID_DECODER_BLIndex, Memory);
	VIndex	 = (int*)  DECODER_MEMORY_GET_ADDRESS(ID_DECODER_VIndex,  Memory);
	Stream	 = (char*) DECODER_MEMORY_GET_ADDRESS(ID_DECODER_Stream,  Memory);


	L = Delta_Pnt;
	
	LastIndex = 0; Io = 0;
	
	while ((L > Small_Stream) && (Max!=0))  {
		BLIndex[LastIndex] = Io; 
		Unpack_LongBitLine(BitLine+(Io>>3), L, Pool, Start, &nextL, Memory);
		Io += (L+8) & 0xFFFFFF8; LastIndex++; L = nextL;

		BLIndex[LastIndex] = Io; 
		Unpack_LongBitLine(BitLine+(Io>>3), L, Pool, Start, &nextL, Memory);
		Io += (L+8) & 0xFFFFFF8; LastIndex++; L = nextL;
		Max--;
	}

	if (!Max) {

	if (LastIndex) {
		for (i=0; i<Delta_Pnt; i++) {
			V = 0;
			for (k = 0; k<LastIndex; k++) {
				Io = BLIndex[k]; BLIndex[k] +=1;
			
				if (!GetBit(BitLine, Io)) {
					QDelta[i] = V; break;
				}

				V = -V +((k&1)^1);
				
				if (k == (LastIndex-1)) QDelta[i]=V; 
			
			}
		}
		return;
	}
	

	}



	if (LastIndex) {
		VIndexPnt = 0;
		for (i=0; i<Delta_Pnt; i++) {
			V = 0;
			for (k = 0; k<LastIndex; k++) {
				Io = BLIndex[k]; BLIndex[k] +=1;
			
				if (!GetBit(BitLine, Io)) {
					QDelta[i] = V; break;
				}

				V = -V +((k&1)^1);
				
				if (k == (LastIndex-1)) { QDelta[i]=V; VIndex[VIndexPnt] = i; VIndexPnt++; }
			
			}
		}
	}



	if ((Max==0) || (L==0)) return;
  

	Energy = GetNumber(Max*L, Pool, Start);


	if (LastIndex==0) {
		Unpack_Unsign_QDelta_Stream(QDelta, L, Pool, Start, Max, Energy, Memory);
		for (i = 0; i<Delta_Pnt; i++) {
			if (QDelta[i]!=0) {
				if (GetBit(Pool,*Start)) QDelta[i]=-QDelta[i];
				*Start+=1;
			}
		}
		return;
	}



	Unpack_Unsign_QDelta_Stream(Stream, L, Pool, Start, Max, Energy, Memory);

	k = 0;
	for (k = 0; k<VIndexPnt; k++) {
		if (Stream[k]!=0) {	
			i = VIndex[k];
			if (GetBit(Pool,*Start)) QDelta[i] -=Stream[k]; else QDelta[i]=-QDelta[i]+Stream[k];
			*Start+=1;
		} 
	}



}





